// new Compile(el, vm)
class Compile{
  constructor(el, vm){
    this.$el = document.querySelector(el);

    this.$vm = vm

    
    if(this.$el){
      // 转换内容为片段
      this.$fragment = this.node2Fragment(this.$el)
      // 执行编译
      this.compile(this.$fragment)
      // 将编译完的html结果追加至$el
      this.$el.appendChild(this.$fragment)
    }

  }
  // 将宿主元素中的代码片段拿出来遍历，这样做比较高效
  node2Fragment(el){
    const frag = document.createDocumentFragment()
    let child
    while(child = el.firstChild){
      frag.appendChild(child)
    }

    return frag
  }

  compile(el){
    const childNodes = el.childNodes
    Array.from(childNodes).forEach(node => {
      // 类型判断
      if(this.isElement(node)){
        // console.log('元素' + node.nodeName)
        const nodeAttrs = node.attributes
        Array.from(nodeAttrs).forEach(attr => {
          const attrName = attr.name
          const exp = attr.value
          if(this.isDirective(attrName)){
            // k-text
            const dir = attrName.substring(2)
            this[dir] && this[dir](node, this.$vm, exp)
          } else if(this.isEvent(attrName)){
            const dir = attrName.substring(1)
            this.eventHandler(node, this.$vm, exp, dir)
          }

        })
      } else if(this.isInterpolation(node)){
        // console.log('文本' + node.textContent)
        this.compileText(node)
      }

      // 递归子节点
      if(node.childNodes && node.childNodes.length > 0){
        this.compile(node)
      }
    })
  }
  // 时间处理器
  eventHandler(node, vm, eventFn, eventName){
    let fn = vm.$options.methods && vm.$options.methods[eventFn]
    if(eventName && fn){
      node.addEventListener(eventName, fn.bind(vm))
    }
  }
  compileText(node){
    // console.log(RegExp.$1)
    // node.textContent = this.$vm.$data[RegExp.$1]
    this.update(node, this.$vm, RegExp.$1, 'text')
  }
  text(node, vm, val){
    this.update(node, vm, val, 'text')
  }
  html(node, vm, val){
    this.update(node, vm, val, 'html')
  }
  // 双向绑定
  model(node, vm, val){
    // 指定input的value属性
    this.update(node, vm, val, 'model')
    // 视图改变data模型
    node.addEventListener('input', e => {
      vm[val] = e.target.value
    })
  }



  // 更新函数
  update(node, vm, exp, dir){
    const updateFn = this[dir+'Updater']
    updateFn && updateFn(node, vm[exp])

    // 依赖收集
    new Watcher(vm, exp, function(value){
      updateFn && updateFn(node, value)
    })
  }


  // 文本更新
  textUpdater(node, value){
    node.textContent = value
  }
  // 文本更新
  htmlUpdater(node, value){
    node.innerHTML = value
  }
  // model更新
  modelUpdater(node, value){
    node.value = value
  }

  isDirective(attrName){
    return attrName.indexOf('k-') == 0
  }
  isEvent(attrName){
    return attrName.indexOf('@') == 0
  }


  isElement(node){
    return node.nodeType === 1
  }
  isInterpolation(node){
    return node.nodeType === 3 && /\{\{(.*)\}\}/.test(node.textContent)
  }

}